﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ColorLib;

namespace ColorPicker
{
    public partial class Form1 : Form
    {
        Bitmap image;
        enum PickerMode { MinError, CubeNormal, CubeLog, CubeSqrt, CubePercent,CubeDistance,CubeMaxError, RyijyPicker };
        PickerMode mode = PickerMode.RyijyPicker;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            comboBox2.Items.Clear();
            foreach (string s in Enum.GetNames(typeof(PickerMode)))
            {
                comboBox2.Items.Add(s);
            }
        }
        void SetImage(string fn)
        {
            Bitmap bm;
            try
            {
                bm = (Bitmap)Bitmap.FromFile(fn);
            }
            catch (Exception )
            {
                MessageBox.Show("Failed to load " + fn);
                return;
            }
            image = bm;
            pictureBox1.Image = image;

            pictureBox2.Image = Process(image);
        }
        Bitmap Process(Bitmap img)
        {
            DateTime t0 = DateTime.Now;
            ColorHistogram h = new ColorHistogram(5);
            if (checkBox1.Checked)
            {
                Bitmap bm2 = new Bitmap(img, new Size(img.Width / 64, img.Height / 64));
                h.Create(bm2);
            }
            else
            {
                h.Create(img);
            }
            DateTime t1 = DateTime.Now;
            List<Color> r = new List<Color>();
            CubePicker cp;
            int numPicks = 20;
            if (textBox1.Text.Length > 0)
            {
                try
                {
                    numPicks = Convert.ToInt32(textBox1.Text);
                }
                catch (Exception ) { }
            }
            switch (mode)
            {
                case PickerMode.CubeNormal:
                    cp = new CubePicker(h.Colors, CubePicker.CubeMode.Normal);
                    r = cp.Select(numPicks);
                    break;
                case PickerMode.CubeLog:
                    cp = new CubePicker(h.Colors, CubePicker.CubeMode.LogCount);
                    r = cp.Select(numPicks);
                    break;
                case PickerMode.CubeSqrt:
                    cp = new CubePicker(h.Colors, CubePicker.CubeMode.SqrtCount);
                    r = cp.Select(numPicks);
                    break;
                case PickerMode.CubePercent:
                    cp = new CubePicker(h.Colors, CubePicker.CubeMode.Percent);
                    r = cp.Select(numPicks);
                    break;
                case PickerMode.CubeDistance:
                    cp = new CubePicker(h.Colors, CubePicker.CubeMode.MaxDistance);
                    r = cp.Select(numPicks);
                    break;
                case PickerMode.CubeMaxError:
                    cp = new CubePicker(h.Colors, CubePicker.CubeMode.MaxError);
                    r = cp.Select(numPicks);
                    break;
                case PickerMode.MinError:
                    MinErrorPicker mep = new MinErrorPicker();
                    mep.Colors = h.Colors;
                    r = mep.Select(numPicks);
                    break;
                case PickerMode.RyijyPicker:
                    RyijyApp.ColorPicker p = new RyijyApp.ColorPicker(h.Colors);
                    p.ColorDistanceMode = RyijyApp.ColorPicker.DistanceMode.RGB;
                    r = p.PickColors(numPicks);
                    break;
            }
            DateTime t2 = DateTime.Now;
            Bitmap bm = new Bitmap(img);

            RecolorFilter rf = new RecolorFilter();
            rf.ColorFilter = new ReplaceColorFilter(r);
            rf.Apply(bm);
            DateTime t3 = DateTime.Now;
            label1.Text = string.Format("times: h={0} s={1} r={2} m={3} c={4}",
                (t1 - t0).TotalSeconds, (t2 - t1).TotalSeconds, (t3 - t2).TotalSeconds, mode.ToString(), r.Count);
            UpdateColorBar(r);
            return bm;

        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBox1.SelectedIndex >= 0)
                if (comboBox1.SelectedItem != null)
                    SetImage(comboBox1.SelectedItem.ToString());
        }

        private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBox2.SelectedIndex >= 0)
            {
                mode = (PickerMode)comboBox2.SelectedIndex;
                if (comboBox1.SelectedItem != null)
                    SetImage(comboBox1.SelectedItem.ToString());
            }
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (comboBox1.SelectedItem != null)
                SetImage(comboBox1.SelectedItem.ToString());

        }
        void UpdateColorBar(List<Color> l)
        {
            float w = pictureBox3.Width / (float)l.Count;
            float h = pictureBox3.Height;
            Bitmap bm = new Bitmap(pictureBox3.Width, pictureBox3.Height);
            float x = 0;

            using (Graphics g = Graphics.FromImage(bm))
            {
                foreach (Color c in l)
                {
                    Brush br = new SolidBrush(c);
                    g.FillRectangle(br, x, 0, w, h);
                    x += w;
                }
            }
            pictureBox3.Image = bm;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            const int testCount = 4000;
            const int testRounds = 20;
            double dt1 = 0;
            double dt2 = 0;

            for (int n = 0; n < testRounds;n++ )
            {
                CubePicker.CubeNode target = new CubePicker.CubeNode();
//                CubePicker.InsertVisitor v = new CubePicker.InsertVisitor(Color.FromArgb(1, 2, 3), 256, Color.Empty, 1);
                System.DateTime t0 = System.DateTime.Now;
                for (int i = 0; i < testCount; i++)
                {
                    Color c = Color.FromArgb(i % 255, (i / 255) % 255, (i * 7) % 255);
                    CubePicker.InsertVisitor v = new CubePicker.InsertVisitor(c, 256, Color.Empty, 1); 
                    target.Apply(v);
                }
                System.DateTime t1 = System.DateTime.Now;

                CubePicker.PickVisitor pv = new CubePicker.PickVisitor();
                for (int i = 0; i < testCount; i++)
                {
                    target.Apply(pv);
                }

                System.DateTime t2 = System.DateTime.Now;
                dt1 += (t1 - t0).TotalSeconds;
                dt2 += (t2 - t1).TotalSeconds;
            }
            int t = testRounds * testCount / 1000;
            label1.Text = string.Format("n={0} insert= {1} ms pick={2} ms", 
                testCount, dt1 / t, dt2 / t);

        }
    }
}
